package com.example.model;

import com.example.config.GameConfig;


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

// 创建一个俄罗斯方块节点类
public class TetrisNode extends JPanel implements KeyListener,Cloneable, Serializable {
    private static final long serialVersionUID = -5809782578272943999L;

    // blockType 代表方块类型
    // turnState代表方块状态
    private boolean isShowGUI = false;


    private int blockType;
    private int score = 0;

    public int turnState;

    private int x;

    private int y;

    private int i = 0;

    private int j = 0;

    public boolean isGameOver = false;
    //小于16视为安全
    private int blockHeight=0;
    private int blockSum = 0;
    
    int []scoreArr = {0,1,3,6,10};
    //每一列个数
    int []colNumArr = new int[9];
    // 定义已经放下的方块x=0-11,y=0-21;
    int[][] map = new int[13][23];


    int blockCount = 0;
    int curRandomNum = GameConfig.getSeed();
    public int turnCount=0;
    public int turnTotal=0;
    //权重
    public int weight = 1;
    public LinkedList<TetrisPath> tetrisPaths = new LinkedList<>();


    @Override
    public Object clone() {
        TetrisNode node = null;
        try{
            node = (TetrisNode)super.clone();
            node.tetrisPaths = (LinkedList<TetrisPath>) this.tetrisPaths.clone();
            node.map = new int[13][23];
            for(int k=0;k<map[0].length;k++) {
                for (int l = 0; l < map.length; l++) {
                    node.map[l][k] = this.map[l][k];
                }
            }
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return node;
    }
    public void setShowGUI(boolean isShowGUI){
        this.isShowGUI = isShowGUI;
    }
    public int getBlockCount(){
        return this.blockCount;
    }
    public int getX(){
        return this.x;

    }
    public int getY(){
        return this.y;
    }
    public void setX(int x){
        this.x = x;
    }
    // 生成新方块的方法
    public void newBlock() {

        //改为固定数值
        int shapeIndex = 0;
        curRandomNum = GameConfig.getRandomNumber(curRandomNum);
        // I,L,J,T,O,S,Z 型方块的概率权重分别为：2,3,3,4,5,6,6（和为29）
        int weightIndex = curRandomNum % 29;
        if (weightIndex >= 0 && weightIndex <= 1) {
            shapeIndex = 0;
        } else if (weightIndex > 1 && weightIndex <= 4) {
            shapeIndex = 1;
        } else if (weightIndex > 4 && weightIndex <= 7) {
            shapeIndex = 2;
        } else if (weightIndex > 7 && weightIndex <= 11) {
            shapeIndex = 3;
        } else if (weightIndex > 11 && weightIndex <= 16) {
            shapeIndex = 4;
        } else if (weightIndex > 16 && weightIndex <= 22) {
            shapeIndex = 5;
        } else if (weightIndex > 22) {
            shapeIndex = 6;
        }

//        blockType = (int) (Math.random() * 1000) % 7;
//        turnState = (int) (Math.random() * 1000) % 4;


        blockType = shapeIndex;
        turnState = (blockCount)%4;
        blockCount++;

//        System.out.println("blockCount="+blockCount+",shapeIndex="+shapeIndex+",turnState="+turnState+",curRandomNum="+curRandomNum);
        x = 2;
        y = 1;
        if (isGameOver(x, y) == 1) {
            isGameOver = true;
//            showMap();
//            initGameState();
        }
        if(isShowGUI){
            repaint();
        }
    }

    private void initGameState() {
        score = 0;
        blockCount=0;
        curRandomNum = GameConfig.getSeed();
        isGameOver = false;
        createMap();
        drawWall();
        newBlock();
        if(blockType==4){
            turnTotal = 1;
        }else if(blockType==0||blockType==5||blockType==6){
            turnTotal = 2;
        }else if(blockType==1||blockType==2||blockType==3){
            turnTotal = 4;
        }else {

        }
        if(isShowGUI){
            repaint();
        }

    }

    // 画围墙
    public void drawWall() {
        for (i = 0; i < 12; i++) {
            map[i][21] = 2;
        }
        for (j = 0; j < 22; j++) {
            map[11][j] = 2;
            map[0][j] = 2;
        }
    }

    // 初始化地图
    public void createMap() {
        for (i = 0; i < 12; i++) {
            for (j = 0; j < 22; j++) {
                map[i][j] = 0;
            }
        }
    }

    // 初始化构造方法
    public TetrisNode() {
        initGameState();
    }

    // 旋转的方法
    public void turn() {
        if(isGameOver){
            return ;
        }
        int tempturnState = turnState;
        turnState = (turnState + 1) % 4;
//        if (blow(x, y, blockType, turnState) == 1) {
//        }

        if (blow(x, y, blockType, turnState) == 0) {
            //旋转失败
            turnState = tempturnState;
        }else{
            turnCount++;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,1000,1000,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
        }
        if(isShowGUI){
            repaint();
        }
    }

    // 左移的方法
    public boolean left() {
        if(isGameOver){
            return false;
        }
        if (blow(x - 1, y, blockType, turnState) == 1) {
            x = x - 1;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,-1,0,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
            if(isShowGUI){
                repaint();
            }

            return true;
        }
        if(isShowGUI){
            repaint();
        }
        return false;
    }
    public int getMaxLeftDistance(){
        int res = 1;
        while(true){
            if(blow(x - res, y, blockType, turnState) != 1){
                res--;
                break;
            }
            res++;
        }
        return res;

    }
    // 左移的方法
    public boolean left(int distance) {
        if(isGameOver){
            return false;
        }

        if (blow(x - distance, y, blockType, turnState) == 1) {
            x = x - distance;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,-distance,0,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
            if(isShowGUI){
                repaint();
            }
            return true;
        }
        if(isShowGUI){
            repaint();
        }
        return false;
    }

    // 右移的方法
    public boolean right() {
        if(isGameOver){
            return false;
        }
        if (blow(x + 1, y, blockType, turnState) == 1) {
            x = x + 1;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,1,0,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
            if(isShowGUI){
                repaint();
            }
            return true;
        }
        if(isShowGUI){
            repaint();
        }
        return false;
    }
    public int getMaxRightDistance(){
        int res = 1;
        while(true){
            if(blow(x + res, y, blockType, turnState) != 1){
                res--;
                break;
            }
            res++;
        }
        return res;

    }
    // 右移的方法
    public boolean right(int distance) {
        if(isGameOver){
            return false;
        }
        if (blow(x + distance, y, blockType, turnState) == 1) {
            x = x + distance;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,distance,0,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
            if(isShowGUI){
                repaint();
            }
            return true;
        }
        if(isShowGUI){
            repaint();
        }
        return false;
    }


    // 下落的方法
    public void down() {
        if(isGameOver){
            return;
        }
        if (blow(x, y + 1, blockType, turnState) == 1) {
            y = y + 1;
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,0,1,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            tetrisPaths.add(tetrisPath);
            delLine();
//            if(checkHole()){
//                weight = 10;
//            }else{
//                weight = 1;
//            }

        }else{
            if (blow(x, y + 1, blockType, turnState) == 0) {
                this.add(x, y, blockType, turnState);
                newBlock();
                delLine();
                TetrisPath tetrisPath = new TetrisPath(blockType,turnState,0,0,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
                this.tetrisPaths.add(tetrisPath);
                turnCount=0;

//                if(checkHole()){
//                    weight = 10;
//                }else{
//                    weight = 1;
//                }
            }
        }
        if(isShowGUI){
            repaint();
        }

    }
//    boolean
//    public boolean isFirstTurn(){
//
//        if(turnCount < turnTotal){
//            //3种情况
//            //1.操作记录为空
//            if(this.tetrisPaths.size() ==0){
//                return true;
//            }
//            //2.为本次操作首节点
//            if(this.tetrisPaths.getLast().isFirstCount){
//                return true;
//            }
//            //3.最后一个操作记录为旋转操作
//            if(this.tetrisPaths.getLast().offsetX ==1000 && this.tetrisPaths.getLast().offsetY ==1000){
//                return true;
//            }
//        }
//
//        return false;
//
//    }
    public int getMaxDownDistance(){
        int res = 0;
        while(true){
            res++;

            if(blow(x , y+res, blockType, turnState) != 1){
                res--;
                break;
            }

        }
        return res;
    }
    public boolean down(int distance) {
        if(isGameOver){
            return false;
        }
        if (blow(x, y + distance, blockType, turnState) == 1) {
            y = y + distance;
            delLine();
            if(isShowGUI){
                repaint();
            }
            return true;
        }else{
            if (blow(x, y + distance, blockType, turnState) == 0) {
                this.add(x, y, blockType, turnState);
                newBlock();
                delLine();
                if(isShowGUI){
                    repaint();
                }
                return true;
            }
        }
        if(isShowGUI){
            repaint();
        }
        return false;
    }
    // 快速下落的方法
    public void quickDown() {
        if(isGameOver){
            return;
        }
        int downMaxDistance =  this.getMaxDownDistance();
        if(downMaxDistance == 0){
            return;
        }

        if ( blow(x, y + downMaxDistance, blockType, turnState) == 1) {
            y = y + downMaxDistance;
            delLine();
            TetrisPath tetrisPath = new TetrisPath(blockType,turnState,0,downMaxDistance,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
            this.tetrisPaths.add(tetrisPath);
        }
        if(isShowGUI){
            repaint();
        }

//        else{
//            if (blow(x, y + 1, blockType, turnState) == 0) {
//                add(x, y, blockType, turnState);
//                newBlock();
//                delLine();
//                TetrisPath tetrisPath = new TetrisPath(blockType,turnState,0,1,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
//                tetrisPaths.add(tetrisPath);
//            }
//        }

//        while(true){
//
//            if (blow(x, y + 1, blockType, turnState) == 1) {
//                y = y + 1;
//                delLine();
//            }
//            if (blow(x, y + 1, blockType, turnState) == 0) {
//                add(x, y, blockType, turnState);
//                newBlock();
//                delLine();
//                TetrisPath tetrisPath = new TetrisPath(blockType,turnState,0,1,blockCount,(tetrisPaths.size()==0 || tetrisPaths.size()>0 && tetrisPaths.getLast().blockCount != blockCount));
//                tetrisPaths.add(tetrisPath);
//                break;
//            }
//        }
    }


    // 是否合法的方法
    public int blow(int x, int y, int blockType, int turnState) {
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
                if (((GameConfig.shapes[blockType][turnState][a * 5 + b] == 1) && (map[x
                        + b + 1][y + a] == 1))
                        || ((GameConfig.shapes[blockType][turnState][a * 5 + b] == 1) && (map[x
                        + b + 1][y + a] == 2))) {

                    return 0;
                }
            }
        }
        return 1;
    }

    // 消行的方法
    public void delLine() {
        int c = 0;
        int sum = 0;
        int n = 0;//1234对应(1 3 6 10)
        for (int b = 0; b < 22; b++) {
            for (int a = 0; a < 12; a++) {
                if (map[a][b] == 1) {
                    if(sum == 0){
                        blockHeight = 21-b;
                    }
                    sum++;
                    c = c + 1;
                    if (c == 10) {
//                        score += 10;
                        n++;
                        for (int d = b; d > 0; d--) {
                            for (int e = 0; e < 11; e++) {
                                map[e][d] = map[e][d - 1];
                            }
                        }
                    }
                }
            }

            c = 0;
        }
        if(n>=1){
            score += sum * scoreArr[n];
            blockSum = sum - n*10;
        }else{
            blockSum = sum;
        }

        if(isShowGUI){
            repaint();
        }
    }

    public int isGameOver(int x, int y) {
        if(isGameOver) return 1;
        if (blow(x, y, blockType, turnState) == 0) {
            return 1;
        }
        return 0;
    }

    // 把当前添加map
    public void add(int x, int y, int blockType, int turnState) {
//        if(x<-2){
//            return;
//        }
        int j = 0;
        for (int a = 0; a < 5; a++) {
            for (int b = 0; b < 5; b++) {
//                System.out.println(x);
//                System.out.println((x + b + 1));
                if (x + b + 1 >=0 && map[x + b + 1][y + a] == 0 & GameConfig.shapes[blockType][turnState][j] ==1) {
                    map[x + b + 1][y + a] = GameConfig.shapes[blockType][turnState][j];
                }
                j++;
            }
        }
    }
    public void showMap(){
        System.out.println(this.toString());
//        System.out.println(this.map);
    }
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();

        for(int k=0;k<map[0].length;k++){
            for(int l=0;l<map.length;l++){

                if(map[l][k] == 2){
                    sb.append("*\t");
                }
                if(map[l][k] == 0){
                    sb.append(" \t");

                }
                if(map[l][k] == 1){
                    sb.append("#\t");
                }
            }
            sb.append("\n");
        }
        sb.append("blockCount:"+blockCount);
        sb.append("\n");
        sb.append("blockHeight:"+blockHeight);
        sb.append("\n");
        sb.append("score:"+score);
        return sb.toString();
    }
    public int getBlockHeight(){
        return blockHeight;
    }

    public int getScore(){
        return this.score;
    }
    public int getTurnState(){ return this.turnState; }
    public int getBlockType(){ return this.blockType; }
    public boolean equalWithNode(TetrisNode tetrisNode){
        return (this.turnState == tetrisNode.turnState && this.x == tetrisNode.x && this.y == tetrisNode.y &&this.blockCount == tetrisNode.blockCount && this.blockType == tetrisNode.blockType);
    }
    //孔洞检测,这样比较省时间
    public boolean checkHole() {

        //[0,1]->[10,20]
        //x->10->0,y->20->1
//        int hole = 0;
        boolean flag = false;
//        int k=0;
        for(i=1;i<11;i++){
            flag = false;
            for(j=0;j<21;j++){
                //记录第一个实体出现位置
                if(map[i][j] == 1){

                    flag = true;
                }
                if(map[i][j] == 0 && flag){
                    return false;
                }

//                System.out.print(map[i][j]+"_"+i+","+j+"_"+k+"\t\t");
//                k++;
            }
//            System.out.println();
        }
        //检测通过
        return true;

    }

    public int getBlockSum(){
        return this.blockSum;
    }

    // 画方块的的方法
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 画当前方块
        for (j = 0; j < 25; j++) {
            if (GameConfig.shapes[blockType][turnState][j] == 1) {
                g.fillRect((j % 5 + x + 1) * 10, (j / 5 + y) * 10, 10, 10);
            }
        }
        // 画已经固定的方块
        for (j = 0; j < 22; j++) {
            for (i = 0; i < 12; i++) {
                if (map[i][j] == 1) {
                    g.fillRect(i * 10, j * 10, 10, 10);

                }
                if (map[i][j] == 2) {
                    g.drawRect(i * 10, j * 10, 10, 10);

                }
            }
        }
        g.drawString("score=" + score, 125, 10);
    }

    // 键盘监听
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_DOWN:
                down();
                break;
            case KeyEvent.VK_UP:
                turn();
                break;
            case KeyEvent.VK_RIGHT:
                right();
                break;
            case KeyEvent.VK_LEFT:
                left();
                break;
            case KeyEvent.VK_SPACE:
                //快速下落
                quickDown();
                break;
            default:
                break;
        }

    }

    // 无用
    public void keyReleased(KeyEvent e) {
    }

    // 无用
    public void keyTyped(KeyEvent e) {
    }
    private int flag = 0;
    // 定时器监听
    class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {

            repaint();
            if (blow(x, y + 1, blockType, turnState) == 1) {
                y = y + 1;
                delLine();
            }
            ;
            if (blow(x, y + 1, blockType, turnState) == 0) {

                if (flag == 1) {
                    add(x, y, blockType, turnState);
                    delLine();
                    newBlock();
                    flag = 0;
                }
                flag = 1;
            }
            ;
        }
    }
    //计算方差
    public int getStdev(){
        int result =0;
        int argv = getBlockSum()/9;
        //更新每列数据
        boolean f = true;
        for(i=1;i<10;i++) {
            f = true;
            for (j = 0; j < 21; j++) {
                if (map[i][j] == 1 && f) {
                    f = false;
                    this.colNumArr[i-1] = 21-j;
                }
            }
        }
        for(int colNum:colNumArr){
            result += (argv-colNum)*(argv-colNum);
        }
        return result;

    }

}
